<?php

Raise::load('db.RaiseDbAdapter');

/**
 * MySqlAdapter RaiseDbAdapter class
 * provides gateway to MySQL related functionalities
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.DataAccess.Adapter
 * @since 1.2
 */
class MySqlAdapter extends RaiseDbAdapter {

    function __construct() {
        if(!function_exists('mysql_connect')){
            throw new RaiseInvalidRequestException('Unable to load MySqlAdapter because the PHP MySQL extension is not installed or enabled.');
        }
    }

    public function connect() {
        $conn = null;
        if($this->connection()->options()->get('persist')){
            $conn = mysql_pconnect($this->connection()->server(), $this->connection()->username(), $this->connection()->password());
        }else{
            $conn = mysql_connect($this->connection()->server(), $this->connection()->username(), $this->connection()->password());
        }
        if(!$conn){
            throw new RaiseRemoteConnectionException('Unable to connect to MySQL Database source.');
        }
        $ok = mysql_select_db($this->connection()->database(), $conn);
        if(!$ok){
            throw new RaiseRemoteConnectionException('Unable to connect to select MySQL database.');
        }
        $this->genericConnection($conn);
    }

    public function disconnect() {
        $ok = mysql_close($this->genericConnection());
        if($ok){
            $this->genericConnection(null);
        }
        return $ok;
    }

    public function escapeString($s) {
        return mysql_real_escape_string($s, $this->genericConnection());
    }

    public function fetchRowArray() {
        return mysql_fetch_row($this->result());
    }

    public function fetchRowObject($class) {
        return mysql_fetch_object($this->result(), $class);
    }

    public function lastInsertId() {
        return mysql_insert_id($this->genericConnection());
    }

    public function query($q) {
        $r = mysql_query($q, $this->genericConnection());
        $this->result($r);
    }

    public function enquote($name) {
        return '`' . $name . '`';
    }

    public function tableColumns($table) {
        $cmd = new RaiseDbCommand($this->connection(), 'SHOW FULL COLUMNS FROM ' . $this->enquote($table) . '');
        $cs = $cmd->executeFetchArrayTable();
        $columns = new RaiseTypedCollection('RaiseDbTableColumn');
        foreach($cs as $t){
            $c = new RaiseDbTableColumn();
            $c->name($t[0]);
            $c->autoIncrement($t[6] == 'auto_increment');
            $c->primaryKey($t[4] == 'PRI');
            $c->null($t[3] != 'NO');
            $c->type($this->translateDataType($t[1]));
            $columns->add($c->name(), $c);
        }
        return $columns;
    }

    public function translateDataType($dataType) {
        $dataType = strtolower(trim($dataType));
        if($dataType == 'tinyint(1)'){
            return RaiseVariable::TYPEBOOLEAN;
        }
        if(strpos($dataType, '(') !== false){
            $dataType = substr($dataType, 0, strpos($dataType, '('));
        }
        switch($dataType){
            case 'bit':
            case 'int':
            case 'integer':
            case 'smallint':
            case 'mediumint':
            case 'bigint':
            case 'tinyint':
            case 'serial':
                return RaiseVariable::TYPEINTEGER;
                break;
            case 'bool':
            case 'boolean':
                return RaiseVariable::TYPEBOOLEAN;
                break;
            case 'float':
            case 'double':
            case 'real':
            case 'double precision':
            case 'decimal':
            case 'dec':
                return RaiseVariable::TYPEDOUBLE;
                break;
            case 'char':
            case 'varchar':
            case 'binary':
            case 'varbinary':
            case 'tinyblob':
            case 'blob':
            case 'mediumblob':
            case 'longblob':
            case 'text':
            case 'tinytext':
            case 'mediumtext':
            case 'longtext':
            case 'enum':
            case 'set':
                return RaiseVariable::TYPESTRING;
                break;
            case 'datetime':
            case 'date':
            case 'timestamp':
            case 'time':
            case 'year':
                return 'RaiseDateTime';
                break;
            default:
                return RaiseVariable::TYPEUNKNOWN;
                break;
        }
    }

    public function rowsAffected() {
        return mysql_affected_rows($this->genericConnection());
    }
    
    public function transactBegin(){
        return 'BEGIN';
    }

    public function transactCommit(){
        return 'COMMIT';

    }

    public function transactRollback(){
        return 'ROLLBACK';
    }

    public function lastError(){
        return mysql_error($this->genericConnection());
    }

    public function __toString() {
        return 'mysql';
    }

}
